public void OnFinishedShouldPassDetailsAboutError()
        {
            // Arrange
            var result = default(FinishedEventArgs?);
            var code   = _fixture.Create <int>();
            var doc    = new Mock <ISettings>().Object;

            var configuration = new WkHtmlToXConfiguration((int)Environment.OSVersion.Platform, runtimeIdentifier: null)
            {
                FinishedAction = eventArgs =>
                {
                    result = eventArgs;
                },
            };

            var sut = new PdfProcessor(configuration, _module.Object)
            {
                ProcessingDocument = doc,
            };

            // Act
            sut.OnFinished(new IntPtr(1), code);

            // Assert
            using (new AssertionScope())
            {
                result !.Document.Should().Be(doc);
                result !.Success.Should().Be(code == 1);
            }
        }
        public void OnProgressChangedShouldPassDetailsAboutError()
        {
            // Arrange
            var progressDescription = _fixture.Create <string>();

            _module.Setup(m => m.GetProgressDescription(It.IsAny <IntPtr>()))
            .Returns(progressDescription);

            var result = default(ProgressChangedEventArgs?);
            var doc    = new Mock <ISettings>().Object;

            var configuration = new WkHtmlToXConfiguration((int)Environment.OSVersion.Platform, runtimeIdentifier: null)
            {
                ProgressChangedAction = eventArgs =>
                {
                    result = eventArgs;
                },
            };

            var sut = new PdfProcessor(configuration, _module.Object)
            {
                ProcessingDocument = doc,
            };

            // Act
            sut.OnProgressChanged(new IntPtr(1));

            // Assert
            using (new AssertionScope())
            {
                result !.Document.Should().Be(doc);
                result !.Description.Should().Be(progressDescription);
            }
        }
Пример #3
0
        static void Main(string[] args)
        {
            string inputPath = @"C:\Tao_Folder\About_Work\CES\test\input\";
            string filename  = @"C:\Tao_Folder\About_Work\CES\test\output\ConcatenatedDocument333.pdf";

            if (File.Exists(filename))
            {
                File.Delete(filename);
            }

            PdfProcessor.MergeMultiplePDFIntoSinglePDF(filename, inputPath);
            // ...and start a viewer.
            Process.Start(filename);


            //SQL_SP_HelpText helpText = new SQL_SP_HelpText();
            ////string connectionString = "Data Source=COSAPXDEV10;SERVER=COSAPXDEV10;User ID=sa;Initial Catalog=$(Catalog);Password=Advent.sa;pooling=yes;Max Pool Size=1110;Connection Lifetime=680;Connect Timeout=660";
            //helpText.SP_HelpText("", "", true);



            //DateMatters();

            //TestDoubleFormat();

            //Test("(if (any? x) sum (/1 x))");
            //Test(":-)");
            //Test(@"I said(it's not (yet) complete). (she didn't listen)");
            //Test("())(");
            //Test(null);
            //Test("");
            //Test("(())()");
            //Test(@"I said(it's not (yet) complete). (she didn't (listen)");
            //Console.ReadLine();
        }
        public void OnWarningShouldPassDetailsAboutError()
        {
            // Arrange
            var result       = default(WarningEventArgs?);
            var errorMessage = _fixture.Create <string>();
            var doc          = new Mock <ISettings>().Object;

            var configuration = new WkHtmlToXConfiguration((int)Environment.OSVersion.Platform, runtimeIdentifier: null)
            {
                WarningAction = eventArgs =>
                {
                    result = eventArgs;
                },
            };

            var sut = new PdfProcessor(configuration, _module.Object)
            {
                ProcessingDocument = doc,
            };

            // Act
            sut.OnWarning(new IntPtr(1), errorMessage);

            // Assert
            using (new AssertionScope())
            {
                result !.Document.Should().Be(doc);
                result !.Message.Should().Be(errorMessage);
            }
        }
        public void RegisterEventsShouldRegisterProgressChangedCallbackWhenSpecified()
        {
            // Arrange
            _module.Setup(m => m.SetProgressChangedCallback(It.IsAny <IntPtr>(), It.IsAny <VoidCallback>()));

            var configuration = new WkHtmlToXConfiguration((int)Environment.OSVersion.Platform, runtimeIdentifier: null)
            {
                ProgressChangedAction = _ => { },
            };

            var sut = new PdfProcessor(configuration, _module.Object);

            // Act
            sut.RegisterEvents(new IntPtr(12));

            // Assert
            using (new AssertionScope())
            {
                _module.Verify(
                    m =>
                    m.SetProgressChangedCallback(
                        It.IsAny <IntPtr>(),
                        It.IsAny <VoidCallback>()),
                    Times.Once);
            }
        }
 public PdfProcessorTest()
 {
     _fixture = new Fixture();
     _module  = new Mock <IWkHtmlToPdfModule>();
     _sut     = new PdfProcessor(
         new WkHtmlToXConfiguration((int)Environment.OSVersion.Platform, null),
         _module.Object);
 }
Пример #7
0
        public void Signing_ExpiredLicense_ThrowsException()
        {
            TestHelper.Job.Profile.OutputFormat = OutputFormat.Pdf;
            TestHelper.Job.Profile.PdfSettings.Signature.CertificateFile = TestHelper.GenerateTestFile(TestFile.CertificationFile_ExpiredP12);

            var ex = Assert.Throws <ProcessingException>(() => PdfProcessor.ProcessPdf(TestHelper.Job));

            Assert.AreEqual(ErrorCode.Signature_Invalid, ex.ErrorCode, "Wrong error code for expired certificate/signature");
        }
Пример #8
0
        protected override void OnMessage(WebSocketSharp.MessageEventArgs e)
        {
            // Basically just echo whatever's sent here

            JObject json          = JObject.Parse(e.Data);
            string  serverRequest = (string)json["BackendRequest"];

            if (string.IsNullOrEmpty(serverRequest))
            {
                Console.WriteLine(" - echoing a message to all sessions");
                // Not a server request, so just echo the contents to everybody
                Sessions.Broadcast(e.Data);
            }

            Console.WriteLine(" - handling a socket message:" + serverRequest);

            switch (serverRequest)
            {
            case "UpdateQueueCounts":
                //Sessions.Broadcast(Program.GetQueueInfoJson());
                break;

            case "AddBitcoinAddress":
                BackendLoop.AddBitcoinAddress((string)json["Address"]);
                break;

            case "Metapackage":
                BackendLoop.ProcessMetapackage(SocketMessage.FromXml((string)json["XmlData"]));
                break;

            case "ConvertPdfHires":
                try
                {
                    JObject newJson = new JObject();
                    newJson["MessageType"] = "EchoBackend";
                    newJson["DocumentId"]  = json["DocumentId"];
                    Sessions.Broadcast(newJson.ToString());

                    PdfProcessor.Rerasterize(Document.FromIdentity(Int32.Parse((string)json["DocumentId"])), PdfProcessor.PdfProcessorOptions.HighQuality | PdfProcessor.PdfProcessorOptions.ForceOrphans);
                }
                catch (Exception exc)
                {
                    JObject newJson = new JObject();
                    newJson["MessageType"]     = "Exception";
                    newJson["ExceptionString"] = exc.ToString();
                    Sessions.Broadcast(newJson.ToString());
                }
                // Convert with high quality -- done on backend with lower priority than the immediate frontend conversion
                break;

            default:
                // do nothing;
                break;
            }
        }
Пример #9
0
        public ActionResult Index()
        {
            using (var reader = new PdfReader(@"S:\git\PdfEditor\form12a.pdf"))
            {
                var processor = new PdfProcessor();
                var html      = processor.ConvertToHtml(reader, 1);

                //return View(html);
                return(Content(html));
            }
        }
Пример #10
0
        public void TestUpdatePDF()
        {
            Application application = new Application();

            application.FirstName = "John";
            application.LastName  = "Johnson";

            String inputPath  = Directory.GetParent(Directory.GetCurrentDirectory()).Parent.FullName + "\\Docs\\BLGLegal Intake Form AcroForm.pdf";
            String outputPath = Directory.GetParent(Directory.GetCurrentDirectory()).Parent.FullName + "\\Docs\\BLGLegal Intake Form_new.pdf";

            PdfProcessor pdfproc = new PdfProcessor();

            pdfproc.UpdatePDF(outputPath, inputPath, application);
        }
Пример #11
0
        public void CheckActions_ResultedFileContainsOnlyImages_ProperlyRotated()
        {
            string inPdfPath = Directory.GetCurrentDirectory() + @"\BlackRectangles1.pdf";

            PdfProcessorTests.FlushResourceToFile(Resources + "BlackRectangles.pdf", inPdfPath);
            string outPdfPath = inPdfPath + ".out.pdf";

            using (var reader = new PdfReader(inPdfPath))
            {
                using (var fs = new FileStream(outPdfPath, FileMode.Create))
                {
                    using (var stamper = new PdfStamper(reader, fs))
                    {
                        using (var render = new GsNetPdfRender(inPdfPath, 150))
                        {
                            var andFilter = new AndFilter(
                                new HasSpecialCsResourceFilter(reader),
                                new NotFilter(new HasFontResourceFilter(reader)),
                                new NotFilter(
                                    new PageHasSpecificKeyFilter(
                                        reader,
                                        RenderPageAction.EstPageRendered,
                                        new PdfBoolean(true))));
                            using (var action = new RenderPageAction(reader, stamper, andFilter, render))
                            {
                                var processor = new PdfProcessor(new List <IPdfAction> {
                                    action
                                });
                                for (int i = 1; i <= reader.NumberOfPages; i++)
                                {
                                    processor.Execute(i);
                                }
                            }
                        }
                    }
                }
            }

            using (var reader = new PdfReader(outPdfPath))
            {
                AssertPageRotation(reader, 1, 0);
                AssertOnlyImageAndImageSize(reader, 1, 1275, 1650);
                AssertPageRotation(reader, 2, 90);
                AssertOnlyImageAndImageSize(reader, 2, 1275, 1650);
                AssertPageRotation(reader, 3, 180);
                AssertOnlyImageAndImageSize(reader, 3, 1275, 1650);
            }
        }
        public void ShouldThrowExceptionWhenNullPassedInModuleConstructor()
        {
            // Arrange

            // ReSharper disable once AssignmentIsFullyDiscarded
#pragma warning disable CS8625   // Cannot convert null literal to non-nullable reference type.
#pragma warning disable IDISP004 // Don't ignore created IDisposable.
            Action action = () => _ = new PdfProcessor(
                new WkHtmlToXConfiguration((int)Environment.OSVersion.Platform, null),
                null);
#pragma warning restore IDISP004 // Don't ignore created IDisposable.
#pragma warning restore CS8625   // Cannot convert null literal to non-nullable reference type.

            // Act & Assert
            action.Should().Throw <ArgumentNullException>();
        }
Пример #13
0
        private static void LongRun(object orderObject)
        {
            RasterizeDocumentHiresOrder order = null;

            try
            {
                order = (RasterizeDocumentHiresOrder)orderObject;
                Document document = Document.FromIdentity(order.DocumentId);
                PdfProcessor.Rerasterize((Document)document, PdfProcessor.PdfProcessorOptions.HighQuality | PdfProcessor.PdfProcessorOptions.ForceOrphans);
                order.Close();
            }
            catch (Exception exception)
            {
                order?.ThrewException(exception);
            }

            if (order != null)
            {
                order.HasTerminated = true;
            }
        }
Пример #14
0
        private static void Main(string[] args)
        {
            // Are we running yet?

            if (!SystemSettings.DatabaseInitialized)
            {
                // will restart the service every 15s until db initialized on OOBE
                // also, the read of DatabaseInitialized can and will fail if
                // we're not initalized enough to even have a database

                throw new InvalidOperationException();
            }

            // Checking for schemata upgrade first of all, after seeing that db exists

            int startupDbVersion = Database.SwarmDb.DbVersion;

            DatabaseMaintenance.UpgradeSchemata();

            testMode = false;

            SystemSettings.BackendHostname = Dns.GetHostName();


            // Other one-time initializations

            FinancialTransactions.FixAllUnsequenced();
            SupportFunctions.OperatingTopology = OperatingTopology.Backend;

            // Begin main loop

            UnixSignal[] killSignals = null;

            if (!Debugger.IsAttached)
            {
                killSignals = new UnixSignal[] { new UnixSignal(Signum.SIGINT), new UnixSignal(Signum.SIGTERM) };
            }

            BotLog.Write(0, "MainCycle", string.Empty);
            BotLog.Write(0, "MainCycle", "-----------------------------------------------");
            BotLog.Write(0, "MainCycle", string.Empty);

            if (args.Length > 0)
            {
                if (args[0].ToLower() == "test")
                {
/*
 *                  BotLog.Write(0, "MainCycle", "Running self-tests");
 *                  HeartBeater.Instance.Beat(heartbeatFile);  // Otherwise Heartbeater.Beat() will fail in various places
 *
 *                  testMode = true;
 *                  Console.WriteLine("Testing All Maintenance Processes (except membership-changing ones).");
 *                  PWLog.Write(PWLogItem.None, 0, PWLogAction.SystemTest, string.Empty, string.Empty);
 *
 *                  Console.WriteLine("\r\n10-second intervals:");
 *                  OnEveryTenSeconds();
 *                  Console.WriteLine("\r\nEvery minute:");
 *                  OnEveryMinute();
 *                  Console.WriteLine("\r\nEvery five minutes:");
 *                  OnEveryFiveMinutes();
 *                  Console.WriteLine("\r\nEvery hour:");
 *                  OnEveryHour();
 *                  Console.WriteLine("\r\nNoon:");
 *                  OnNoon();
 *                  Console.WriteLine("\r\nMidnight:");
 *                  OnMidnight();
 */

                    Console.WriteLine("Testing database access...");

                    Console.WriteLine(SwarmDb.GetDatabaseForReading().GetPerson(1).Name);
                    Console.WriteLine(SwarmDb.GetDatabaseForReading().GetPerson(1).PasswordHash);

                    Console.WriteLine("Creating OutboundComm...");

                    OutboundComm.CreateNotification(null, NotificationResource.System_Startup_Backend);

                    Console.WriteLine("Transmitting...");

                    OutboundComms comms = OutboundComms.GetOpen();

                    Console.WriteLine("{0} open items in outbound comms.", comms.Count);

                    foreach (OutboundComm comm in comms)
                    {
                        if (comm.TransmitterClass != "Swarmops.Utility.Communications.CommsTransmitterMail")
                        {
                            throw new NotImplementedException();
                        }

                        ICommsTransmitter transmitter = new CommsTransmitterMail();

                        OutboundCommRecipients recipients = comm.Recipients;
                        PayloadEnvelope        envelope   = PayloadEnvelope.FromXml(comm.PayloadXml);

                        foreach (OutboundCommRecipient recipient in recipients)
                        {
                            transmitter.Transmit(envelope, recipient.Person);
                        }
                    }


                    Console.Write("\r\nAll tests run. Waiting for mail queue to flush... ");
                    while (!MailTransmitter.CanExit)
                    {
                        Thread.Sleep(50);
                    }

                    Console.WriteLine("done.");
                    BotLog.Write(0, "MainCycle", "Exiting self-tests");
                    return;
                }

                if (args[0].ToLower() == "console")
                {
                    Console.WriteLine("\r\nRunning Swarmops-Backend in CONSOLE mode.\r\n");

                    // -------------------------------------------------------------------------------------
                    // -------------------------------------------------------------------------------------
                    // -------------------------------------------------------------------------------------

                    // -----------------------    INSERT ANY ONE-OFF ACTIONS HERE  -------------------------


                    Console.Write("\r\nWaiting for mail queue to flush... ");

                    while (!MailTransmitter.CanExit)
                    {
                        Thread.Sleep(50);
                    }

                    Console.WriteLine("done.");

                    return;
                }

                if (args[0].ToLowerInvariant() == "pdfregen")
                {
                    if (args.Length > 1)
                    {
                        int docId = Int32.Parse(args[1]);
                        PdfProcessor.Rerasterize(Document.FromIdentity(docId));
                    }
                    else
                    {
                        Console.WriteLine("Regenerating all bitmaps from PDF uploads.");
                        PdfProcessor.RerasterizeAll();
                        Console.WriteLine("Done.");
                    }

                    return;
                }


                if (args[0].ToLower() == "rsm")
                {
                    Console.WriteLine("Testing character encoding: räksmörgås RÄKSMÖRGÅS");
                    return;
                }
            }

            /*
             * MailMessage message = new MailMessage();
             * message.From = new MailAddress(Strings.MailSenderAddress, Strings.MailSenderName);
             * message.To.Add (new MailAddress ("*****@*****.**", "Rick Falkvinge (Piratpartiet)"));
             * message.Subject = "Räksmörgåsarnas ékÖNÖMÏåvdëlnïng";
             * message.Body = "Hejsan hoppsan Räksmörgåsar.";
             * message.BodyEncoding = Encoding.Default;
             * message.SubjectEncoding = Encoding.Default;
             *
             * SmtpClient smtpClient = new SmtpClient ("localhost");
             * smtpClient.Credentials = null; // mono bug
             * smtpClient.Send (message);*/

            Console.WriteLine(" * Swarmops Backend starting");

            BotLog.Write(0, "MainCycle", "Backend STARTING");

            // Disable certificate checking due to Mono not installing with a certificate repository - this is UTTERLY broken

            SupportFunctions.DisableSslCertificateChecks(); // MONO BUG/MISFEATURE: Mono has no root certificates, so can't verify cert

            // Tell sysop we're starting

            OutboundComm.CreateNotification(null, NotificationResource.System_Startup_Backend);

            // Check for existence of installation ID. If not, create one. Warning: has privacy implications when communicated.

            if (Persistence.Key["SwarmopsInstallationId"] == string.Empty)
            {
                Persistence.Key["SwarmopsInstallationId"] = Guid.NewGuid().ToString();
            }

            // Check for existence of bitcoin hotwallet root

            BitcoinUtility.VerifyBitcoinHotWallet();

            // Initialize backend socket server

            int backendSocketPort = SystemSettings.WebsocketPortBackend;

            _socketServer = new WebSocketServer(backendSocketPort);
            _socketServer.AddWebSocketService <BackendServices>("/Backend");
            _socketServer.Start();

            // Initialize socket client to Blockchain.Info (pending our own services)

            using (
                _blockChainInfoSocket =
                    new WebSocket("wss://ws.blockchain.info/inv?api_code=" + SystemSettings.BlockchainSwarmopsApiKey))
            {
                // Begin maintenance loop

                DateTime cycleStartTime = DateTime.UtcNow;
                DateTime cycleEndTime;

                int lastSecond = cycleStartTime.Second;
                int lastMinute = cycleStartTime.Minute;
                int lastHour   = cycleStartTime.Hour;

                bool exitFlag = false;

                _blockChainInfoSocket.OnOpen    += new EventHandler(OnBlockchainOpen);
                _blockChainInfoSocket.OnError   += new EventHandler <ErrorEventArgs>(OnBlockchainError);
                _blockChainInfoSocket.OnClose   += new EventHandler <CloseEventArgs>(OnBlockchainClose);
                _blockChainInfoSocket.OnMessage += new EventHandler <MessageEventArgs>(OnBlockchainMessage);

                _blockChainInfoSocket.Connect();

                while (!exitFlag) // exit is handled by signals handling at end of loop
                {
                    BotLog.Write(0, "MainCycle", "Cycle Start");

                    cycleStartTime = DateTime.UtcNow;
                    cycleEndTime   = cycleStartTime.AddSeconds(10);

                    try
                    {
                        OnEveryTenSeconds();

                        if (cycleStartTime.Second < lastSecond)
                        {
                            OnEveryMinute();

                            if (cycleStartTime.Minute % 5 == 0)
                            {
                                OnEveryFiveMinutes();
                            }
                        }

                        if (cycleStartTime.Minute < lastMinute)
                        {
                            OnEveryHour();

                            if (DateTime.Now.Hour == 10 && DateTime.Today.DayOfWeek == DayOfWeek.Tuesday)
                            {
                                OnTuesdayMorning();
                            }

                            if (DateTime.Now.Hour == 7 && DateTime.Today.DayOfWeek == DayOfWeek.Monday)
                            {
                                OnMondayMorning();
                            }
                        }

                        if (cycleStartTime.Hour >= 12 && lastHour < 12)
                        {
                            OnNoon();
                        }

                        if (cycleStartTime.Hour < lastHour)
                        {
                            OnMidnight();
                        }
                    }

                    catch (Exception e)
                    {
                        // Note each "OnEvery..." catches its own errors and sends Exception mails,
                        // so that failure in one should not stop the others from running. This particular
                        // code should never run.

                        ExceptionMail.Send(new Exception("Failed in swarmops-backend main loop", e), true);
                    }

                    lastSecond = cycleStartTime.Second;
                    lastMinute = cycleStartTime.Minute;
                    lastHour   = cycleStartTime.Hour;

                    // Wait for a maximum of ten seconds (the difference between cycleStartTime and cycleEndTime)

                    int      iterationCount = 0;
                    DateTime utcNow         = DateTime.UtcNow;
                    while (utcNow < cycleEndTime && !exitFlag)
                    {
                        int signalIndex = 250;

                        // Handle important service orders (those that can't be lost in a random loss
                        // of connection of a socket):

                        BackendServiceOrders backendOrders = BackendServiceOrders.GetNextBatch(5);
                        backendOrders.Execute(); // takes at most 250ms per BSO reqs

                        // Block until a SIGINT or SIGTERM signal is generated, or 1/4 second has passed.
                        // However, we can't do that in a development environment - it won't have the
                        // Mono.Posix assembly, and won't understand UnixSignals. So people running this in
                        // a dev environment will need to stop it manually.

                        if (!Debugger.IsAttached)
                        {
                            signalIndex = UnixSignal.WaitAny(killSignals, 250);
                        }
                        else
                        {
                            TimeSpan timeLeft = (cycleEndTime - utcNow);

                            BotLog.Write(0, "MainCycle Debug",
                                         string.Format(CultureInfo.InvariantCulture,
                                                       "Waiting for {0:F2} more seconds for cycle end",
                                                       timeLeft.TotalMilliseconds / 1000.0));
                            Thread.Sleep(250);
                        }

                        if (signalIndex < 250)
                        {
                            exitFlag = true;
                            Console.WriteLine("Caught signal " + killSignals[signalIndex].Signum + ", exiting");
                            BotLog.Write(0, "MainCycle",
                                         "EXIT SIGNAL (" + killSignals[signalIndex].Signum + "), terminating backend");
                        }

                        utcNow = DateTime.UtcNow;

                        // Every second, send an internal heartbeat

                        if (iterationCount++ % 4 == 0)
                        {
                            InternalHeartbeat();
                        }
                    }
                }
            }

            Console.WriteLine(" * Swarmops Backend stopping");
            BotLog.Write(0, "MainCycle", "BACKEND EXITING, sending backend-termination notices");

            /*
             * if (HeartBeater.Instance.WasKilled)
             * {
             *  // removed unconditional delete, cron job that restarts bot uses it to know that it is intentionally down.
             *  ExceptionMail.Send(new Exception("HeartBeater triggered restart of Swarmops Backend. Will commence after 800 seconds."), false);
             * }*/

            BotLog.Write(0, "MainCycle", "...done");

            /*
             * while (!MailTransmitter.CanExit)
             * {
             *  System.Threading.Thread.Sleep(50);
             * }*/

            _socketServer.Stop();

            Thread.Sleep(2000);
        }
        private static void ProcessExpensifyUploadThread(object args)
        {
            string       guidProgress = ((ProcessThreadArguments)args).GuidProgress;
            string       guidFiles    = ((ProcessThreadArguments)args).GuidFiles;
            Person       currentUser  = ((ProcessThreadArguments)args).CurrentUser;
            Organization organization = ((ProcessThreadArguments)args).Organization;

            ProgressBarBackend progress = new ProgressBarBackend(guidProgress);

            try
            {
                Documents documents = Documents.RecentFromDescription(guidFiles);
                progress.Set(2); // indicate more life

                if (documents.Count != 1)
                {
                    return; // abort
                }

                Document uploadedDoc = documents[0];

                // TODO: ATTEMPT TO DETERMINE CURRENCY FROM FILE, USING ORIGINAL CURRENCY + ORIGINAL AMOUNT

                string csvEntire;

                using (StreamReader reader = uploadedDoc.GetReader(1252))
                {
                    csvEntire = reader.ReadToEnd();
                }

                GuidCache.Set("ExpensifyRaw-" + guidFiles, csvEntire);

                string[] csvLines   = csvEntire.Split(new char[] { '\r', '\n' });
                string[] fieldNames = csvLines[0].Split(',');

                // Map fields to column indexes

                Dictionary <ExpensifyColumns, int> fieldMap = new Dictionary <ExpensifyColumns, int>();

                for (int loop = 0; loop < fieldNames.Length; loop++)
                {
                    switch (fieldNames[loop].ToLowerInvariant().Trim('\"'))
                    {
                    case "timestamp":
                        fieldMap[ExpensifyColumns.Timestamp] = loop;
                        break;

                    case "amount":
                        fieldMap[ExpensifyColumns.AmountFloat] = loop;
                        break;

                    case "merchant":
                        fieldMap[ExpensifyColumns.Merchant] = loop;
                        break;

                    case "comment":
                        fieldMap[ExpensifyColumns.Comment] = loop;
                        break;

                    case "category":
                        fieldMap[ExpensifyColumns.CategoryCustom] = loop;
                        break;

                    case "mcc":
                        fieldMap[ExpensifyColumns.CategoryStandard] = loop;
                        break;

                    case "vat":
                        fieldMap[ExpensifyColumns.VatFloat] = loop;
                        break;

                    case "original currency":
                        fieldMap[ExpensifyColumns.OriginalCurrency] = loop;
                        break;

                    case "original amount":
                        fieldMap[ExpensifyColumns.OriginalCurrencyAmountFloat] = loop;
                        break;

                    case "receipt":
                        fieldMap[ExpensifyColumns.ReceiptUrl] = loop;
                        break;

                    default:
                        // ignore any unknown fields
                        break;
                    }
                }

                ExpensifyColumns[] requiredData =
                {
                    ExpensifyColumns.AmountFloat,
                    ExpensifyColumns.CategoryCustom,
                    ExpensifyColumns.CategoryStandard,
                    ExpensifyColumns.Comment,
                    ExpensifyColumns.Merchant,
                    ExpensifyColumns.OriginalCurrency,
                    ExpensifyColumns.OriginalCurrencyAmountFloat,
                    ExpensifyColumns.ReceiptUrl,
                    ExpensifyColumns.Timestamp
                };

                foreach (ExpensifyColumns requiredColumn in requiredData)
                {
                    if (!fieldMap.ContainsKey(requiredColumn))
                    {
                        // Abort as invalid file

                        GuidCache.Set("Results-" + guidFiles, new AjaxCallExpensifyUploadResult
                        {
                            Success        = false,
                            ErrorType      = "ERR_INVALIDCSV",
                            DisplayMessage = Resources.Pages.Financial.FileExpenseClaim_Expensify_Error_InvalidCsv
                        });

                        progress.Set(100);     // terminate progress bar, causes retrieval of result

                        documents[0].Delete(); // prevents further processing

                        return;                // terminates thread
                    }
                }

                // TODO: Much more general-case error conditions if not all fields are filled

                bool vatEnabled = organization.VatEnabled;

                if (vatEnabled && !fieldMap.ContainsKey(ExpensifyColumns.VatFloat))
                {
                    // Error: Organization needs a VAT field

                    GuidCache.Set("Results-" + guidFiles, new AjaxCallExpensifyUploadResult
                    {
                        Success        = false,
                        ErrorType      = "ERR_NEEDSVAT",
                        DisplayMessage = Resources.Pages.Financial.FileExpenseClaim_Expensify_Error_NeedsVat
                    });

                    progress.Set(100);     // terminate progress bar, causes retrieval of result

                    documents[0].Delete(); // prevents further processing

                    return;                // terminates thread
                }

                List <ExpensifyRecord> recordList = new List <ExpensifyRecord>();

                CsvHelper.Configuration.Configuration config = new CsvHelper.Configuration.Configuration();
                config.HasHeaderRecord = true;

                using (TextReader textReader = new StringReader(csvEntire))
                {
                    CsvReader csvReader = new CsvReader(textReader, config);
                    csvReader.Read(); // bypass header record -- why isn't this done automatically?

                    while (csvReader.Read())
                    {
                        ExpensifyRecord newRecord            = new ExpensifyRecord();
                        Int64           amountExpensifyCents =
                            newRecord.AmountCents =
                                Formatting.ParseDoubleStringAsCents(
                                    csvReader.GetField(fieldMap[ExpensifyColumns.AmountFloat]),
                                    CultureInfo.InvariantCulture);
                        newRecord.OriginalCurrency =
                            Currency.FromCode(csvReader.GetField(fieldMap[ExpensifyColumns.OriginalCurrency]));
                        newRecord.OriginalAmountCents =
                            Formatting.ParseDoubleStringAsCents(
                                csvReader.GetField(fieldMap[ExpensifyColumns.OriginalCurrencyAmountFloat]),
                                CultureInfo.InvariantCulture);
                        newRecord.Timestamp = DateTime.Parse(csvReader.GetField(fieldMap[ExpensifyColumns.Timestamp]));

                        bool amountNeedsTranslation = false;

                        if (newRecord.OriginalCurrency.Identity != organization.Currency.Identity)
                        {
                            amountNeedsTranslation = true;

                            // May or may not be the same as Expensify calculated

                            newRecord.AmountCents =
                                new Money(newRecord.OriginalAmountCents, newRecord.OriginalCurrency, newRecord.Timestamp)
                                .ToCurrency(organization.Currency).Cents;
                        }

                        newRecord.Description = csvReader.GetField(fieldMap[ExpensifyColumns.Merchant]);

                        string comment = csvReader.GetField(fieldMap[ExpensifyColumns.Comment]).Trim();
                        if (!string.IsNullOrEmpty(comment))
                        {
                            newRecord.Description += " / " + comment;
                        }
                        newRecord.CategoryCustom   = csvReader.GetField(fieldMap[ExpensifyColumns.CategoryCustom]);
                        newRecord.CategoryStandard = csvReader.GetField(fieldMap[ExpensifyColumns.CategoryStandard]);
                        newRecord.ReceiptUrl       = csvReader.GetField(fieldMap[ExpensifyColumns.ReceiptUrl]);

                        newRecord.Guid = Guid.NewGuid().ToString();

                        if (vatEnabled)
                        {
                            Int64 vatOriginalCents =
                                Formatting.ParseDoubleStringAsCents(
                                    csvReader.GetField(fieldMap[ExpensifyColumns.VatFloat]),
                                    CultureInfo.InvariantCulture);

                            if (amountNeedsTranslation)
                            {
                                double vatRatio = vatOriginalCents / (double)amountExpensifyCents;
                                newRecord.VatCents = (Int64)(newRecord.AmountCents * vatRatio);
                            }
                            else
                            {
                                newRecord.VatCents = vatOriginalCents;
                            }
                        }

                        recordList.Add(newRecord);
                    }
                }

                progress.Set(10);

                // We now need to get all the receipt images. This is a little tricky as we don't have the URL
                // of the receipt directly, we only have the URL of a webpage that contains JavaScript code
                // to fetch the receipt image.

                // Get relative date part

                string relativePath = Document.DailyStorageFolder.Substring(Document.StorageRoot.Length);

                // Get all receipts

                for (int loop = 0; loop < recordList.Count; loop++)
                {
                    progress.Set(loop * 90 / recordList.Count + 10);

                    using (WebClient client = new WebClient())
                    {
                        string receiptResource = client.DownloadString(recordList[loop].ReceiptUrl);

                        // We now have the web page which holds information about where the actual receipt is located.

                        Regex regex = new Regex(@"\s*var transaction\s*=\s*(?<jsonTxInfo>{.*});", RegexOptions.Multiline);
                        Match match = regex.Match(receiptResource);
                        if (match.Success)
                        {
                            string  txInfoString = match.Groups["jsonTxInfo"].ToString();
                            JObject txInfo       = JObject.Parse(txInfoString);
                            recordList[loop].ExtendedInfo = txInfoString;

                            string expensifyFileName = (string)txInfo["receiptFilename"];
                            string actualReceiptUrl  = "https://s3.amazonaws.com/receipts.expensify.com/" +
                                                       expensifyFileName;
                            string newGuidString = recordList[loop].Guid;

                            string fullyQualifiedFileName = Document.DailyStorageFolder + newGuidString;
                            string relativeFileName       = relativePath + newGuidString;

                            client.DownloadFile(actualReceiptUrl, fullyQualifiedFileName);
                            recordList[loop].ReceiptFileNameHere = newGuidString;

                            // If original file name ends in PDF, initiate conversion.

                            if (expensifyFileName.ToLowerInvariant().EndsWith(".pdf"))
                            {
                                // Convert low resolution

                                Documents docs = new PdfProcessor().RasterizeOne(fullyQualifiedFileName,
                                                                                 recordList[loop].Description, newGuidString, currentUser, organization);

                                recordList[loop].Documents = docs;

                                // Ask backend for high-res conversion

                                RasterizeDocumentHiresOrder backendOrder =
                                    new RasterizeDocumentHiresOrder(docs[0]);
                                backendOrder.Create();
                            }
                            else
                            {
                                Document doc = Document.Create(relativePath + newGuidString, expensifyFileName, 0,
                                                               newGuidString, null,
                                                               currentUser);

                                recordList[loop].Documents = Documents.FromSingle(doc);
                            }
                        }
                    }
                }



                // We now have the individual expenses and all accompanying receipts.
                // Create the expense claim group, then the individual expense records,
                // and assign the Documents to the records and the records to the Group,
                // so the user can review all of it.


                // TODO: Suggest initial budgets

                List <ExpensifyOutputRecord> outputRecords = new List <ExpensifyOutputRecord>();

                string docString =
                    "<a href='/Pages/v5/Support/StreamUpload.aspx?DocId={0}&hq=1' data-caption=\"{1}\" class='FancyBox_Gallery' data-fancybox='{2}'>";

                string documentsAll = String.Empty;

                foreach (ExpensifyRecord record in recordList)
                {
                    foreach (Document document in record.Documents)
                    {
                        documentsAll += String.Format(docString, document.Identity,
                                                      document.ClientFileName.Replace("\"", "'"),
                                                      "D" + record.Documents[0].Identity.ToString(CultureInfo.InvariantCulture));
                    }
                }

                AjaxCallExpensifyUploadResult result = new AjaxCallExpensifyUploadResult
                {
                    Success   = true,
                    Data      = FormatExpensifyOutputRecords(recordList),
                    Footer    = FormatExpensifyFooter(recordList),
                    Documents = documentsAll
                };

                GuidCache.Set("Results-" + guidFiles, result);
                GuidCache.Set("ExpensifyData-" + guidFiles, recordList);
            }
            catch (Exception exception)
            {
                // Abort as exception

                GuidCache.Set("Results-" + guidFiles, new AjaxCallExpensifyUploadResult
                {
                    Success        = false,
                    ErrorType      = "ERR_EXCEPTION",
                    DisplayMessage = exception.ToString()
                });
            }
            finally
            {
                progress.Set(100); // terminate progress bar, causes retrieval of result
            }
        }
Пример #16
0
        protected override void OnMessage(WebSocketSharp.MessageEventArgs e)
        {
            // Basically just echo whatever's sent here

            Console.WriteLine(" - a client says " + e.Data);

            JObject json          = JObject.Parse(e.Data);
            string  serverRequest = (string)json["ServerRequest"];

            if (string.IsNullOrEmpty(serverRequest))
            {
                // Not a server request, so just echo the contents to everybody
                Sessions.Broadcast(e.Data);
            }

            switch (serverRequest)
            {
            case "AddBitcoinAddress":
                FrontendLoop.AddBitcoinAddress((string)json["Address"]);
                break;

            case "Metapackage":
                ProcessMetapackage((string)json["XmlData"]);
                break;

            case "Ping":
                // TODO: Request heartbeat from backend
                // Sessions.Broadcast("{\"messageType\":\"Heartbeat\"}");
                break;

            case "ConvertPdf":
                try
                {
                    JArray pdfFilesArray       = (JArray)json["PdfFiles"];
                    JArray pdfClientNamesArray = (JArray)json["ClientFileNames"];

                    List <RasterizationTarget> rasterizationTargets = new List <RasterizationTarget>();
                    for (int loop = 0; loop < pdfFilesArray.Count; loop++)
                    {
                        rasterizationTargets.Add(new RasterizationTarget
                        {
                            FullyQualifiedFileName = Document.StorageRoot + (string)pdfFilesArray[loop],
                            ClientFileName         = (string)pdfClientNamesArray[loop]
                        });
                    }

                    PdfProcessor pdfMaker = new PdfProcessor();
                    pdfMaker.RasterizationProgress += BroadcastGuidProgress;
                    pdfMaker.RasterizeMany(rasterizationTargets.ToArray(), (string)json["Guid"], _authority.Person,
                                           _authority.Organization);
                }
                catch (Exception exc)
                {
                    Sessions.Broadcast("{\"messageType\":\"Debug\",\"data\":\"Exception - " + exc.GetType() + " - " + exc.ToString().Replace("\"", "\\\"") + "\"}");
                }

                break;

            case "ConvertPdfHires":
                // Send to backend
                JObject backendRequest = new JObject();
                backendRequest["BackendRequest"] = "ConvertPdfHires";
                backendRequest["DocumentId"]     = json["DocumentId"];
                FrontendLoop.SendMessageUpstream(backendRequest);
                break;

            default:
                // do nothing;
                break;
            }
        }